#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define BUF_SIZE 1024

//COVID-19 疫情API
//#define HOST "coronavirus-tracker-api.herokuapp.com"
//#define URI "/v2/latest"

//下载文件
//#define HOST "downloads.raspberrypi.org"
//#define URI "/imager/imager.exe"

//百度主页
//#define HOST "www.baidu.com"
//#define URI "/"

//中央气象台 天气API
//#define HOST "www.nmc.cn"
//#define URI "/f/rest/real/57036"

//新浪财经 股票API
//#define HOST "hq.sinajs.cn"
//#define URI "/list=s_sh000001,s_sz000001"

//巴法云微信推送API
#define HOST "api.bemfa.com"
#define URI "/api/wechat/v1/weget.php?uid=4e78c607dbbc9f4d6b5c16ffa5622fb7&type=1&device=test&msg=hello"

int parse_status(char *line)
{
	char protocol[10];
	int code;
	char reason[100] = {0};

	//puts(line);
	sscanf(line, "%9s %3d %99[a-zA-Z ]", protocol, &code, reason);

	printf("status line:\n");
	printf("protocol = %s\n", protocol);
	printf("code = %d\n", code);
	printf("reason = %s\n", reason);

	return code;
}

int chunked = 0;
size_t content_length = 0;

void print_field(char *line)
{
	char key[100];
	char value[512];
	sscanf(line, "%99[^:]: %511[^\r]", key, value);
	printf("%s = %s\n", key, value);
	if (!strncmp(key, "Transfer-Encoding", strlen("Transfer-Encoding")))
	{
		if (strstr(value, "chunked"))
		{
			chunked = 1;
		}
	}

	if (!strcmp(key, "Content-Length"))
	{
		content_length = atoi(value);
	}
}

int main()
{
	struct addrinfo hints;
	struct addrinfo *result, *rp;
	int err;
	int sfd;
	FILE *sfp;
	char buf[BUF_SIZE];

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	err = getaddrinfo(HOST, "80", &hints, &result);
	if (err)
	{
		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
		exit(EXIT_FAILURE);
	}

	for (rp = result; rp != NULL; rp = rp->ai_next)
	{
		sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
		if (sfd < 0)
		{
			continue;
		}

		if (connect(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
		{
			printf("server connected\n");
			break;
		}

		perror("connect");

		close(sfd);
	}

	if (!rp)
	{
		exit(EXIT_FAILURE);
	}

	freeaddrinfo(result);

	sfp = fdopen(sfd, "r+");
	if (!sfp)
	{
		perror("fdopen");
		exit(EXIT_FAILURE);
	}

	fprintf(sfp, "GET " URI " HTTP/1.1\r\n");
	fprintf(sfp, "Host: " HOST "\r\n");
	fprintf(sfp, "Connection: close\r\n");
	fprintf(sfp, "\r\n");

	//处理响应报文状态行
	fgets(buf, BUF_SIZE, sfp);
	if (parse_status(buf) != 200)
	{
		return 1;
	}

	puts("\nresponse header:");
	//处理响应头，读取到空行后结束循环
	while (fgets(buf, BUF_SIZE, sfp) && buf[0] != '\r')
	{
		print_field(buf);
	}

	puts("\nresponse body:");
	if (chunked)
	{
		//处理分块
		while(fgets(buf, BUF_SIZE, sfp)) //获取分块长度
		{
			long chunk_size = strtol(buf, NULL, 16);
			if (!chunk_size) break; //响应报文结束，跳出循环
			//printf("chunk size: %ld\n", chunk_size);
			size_t n = fread(buf, 1, chunk_size, sfp);
			fwrite(buf, 1, n, stdout);
		}
	}
	else
	{
		//printf("length = %Zd\n", content_length);
		//处理响应内容
		size_t size = content_length > BUF_SIZE ? BUF_SIZE : content_length;
		size_t n = 0;
		while ((n = fread(buf, 1, size, sfp)))
		{
			fwrite(buf, 1, n, stdout);
			if (n == content_length) break;
		}
	}

	puts("\n");

	fclose(sfp);

	return 0;
}
